#include "bitmap_image.hpp"
#include "GUI.h"
#include <sstream>

bool GUI::LoadTextureBMP(){


	glGenTextures(5, texture );
	//const char *filename = "bar.bmp";
	texture[0] = SetTexture("bar.bmp", 0, 280, 51);
	texture[1] = SetTexture("pointer.bmp", 1, 32, 32);
	texture[2] = SetTexture("button_check.bmp", 2, 25, 25);
	texture[3] = SetTexture("button_default.bmp", 3, 64, 64);
	texture[4] = SetTexture("frame.bmp", 4, 250, 800);
	
	for(int i = 0; i<5; i++)
	if(texture[i] == -1){
		printf("false\n");
		return false;
	}

	
	

	return true;

}//LoadTextureBMP

GLuint GUI::SetTexture( const char * filename, int num, int width, int height)
{

	
  unsigned char * data;

  FILE * file;

  fopen_s(&file, filename, "rb" );

  if ( file == NULL ) return -1;
  data = (unsigned char *)malloc( width * height * 3 );
  fread( data, width * height * 3, 1, file );
  fclose( file );

 for(int i = 0; i < width * height ; ++i)
{
   int index = i*3;
   unsigned char B,R;
   B = data[index];
   R = data[index+2];

   data[index] = R;
   data[index+2] = B;

}



glBindTexture( GL_TEXTURE_2D, texture[num] );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_REPLACE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_REPEAT );


	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_REPEAT );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT );

bitmap_image *image = new bitmap_image(filename);
image->bgr_to_rgb();
	gluBuild2DMipmaps( GL_TEXTURE_2D, 3, image->width(), image->height(),GL_RGB, GL_UNSIGNED_BYTE, image->data() );
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image->width(), image->height(),0, GL_RGB, GL_UNSIGNED_BYTE, image->data() );

//gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,GL_RGB, GL_UNSIGNED_BYTE, data );
//glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height,0, GL_RGB, GL_UNSIGNED_BYTE, data );
free( data );

return texture[num];
}

void GUI::SetMagnet(){

			
	/*
	if(ratio>1.0f)
		ratio = 1.0f;
	else if(ratio <0.05f)
		ratio = 0.05f;
*/


	
	ratio = m_slide[1].prop;



	/*
	Vector2 pos(x,y);
	pos *= 10;
	adjSize();
	if(!mo)
		mo = new MagnetObject(1, pos , size, ori, Vector2(0,0), 0.f);

	mo->reset(pos, size, ori);
	mo->drawme();
	glutPostRedisplay();
	*/


	/*
	MagnetObject *mo;
	Mag *pmag;
	float ratio = 0.3f;

	Vector2 pos;
	Vector2 midpoint = (start + end)/2;

	Vector2 dir = end - start;
	Vector2 mm = dir;

	Vector2 ortho(-dir.y(), dir.x());

	float len = dir.length();

	if(len < 0.01f)
		return ;

	float ortholen = len * ratio;

	ortho = ortho.normalize() * ortholen;


	mo = new MagnetObject(1, midpoint, dir, ortho, mm, 0.f);

	Vector2 startpos = start - ortho/2.f;
	startpos.PrintVector2();
	for(float x = 0; x < len; x+= len/10.f){

		Vector2 point = startpos + dir.normalized() * x;
		for(float y = 0; y<ortholen ; y += ortholen * ratio){

			Vector2 temp = ortho.normalized() * y;

			pos = point+ temp;
			pmag = new Mag(pos, mm);
			mo->AddvMagnet(pmag);

		}
	}//for(xy)


	m_particleSystem->wbPlaceMagnet(mo);
	*/

	Vector2 pos = (start + end)/2.f;
	if(!mo)
		mo = new MagnetObject(1, pos , size, ori, Vector2(0,0), m_particleSystem->GetParticleVolume());

	Vector2 dir = end - start;
	Vector2 ortho(-dir.y(), dir.x());

	ortho = ortho * ratio;

	float len = dir.length();
	
	if(len < 0.02f) {
		return ;
	}

	mo->SetGUIPos(start, end);

	Vector2 mm = m_slide[0].prop * dir;
	mo->SetMMScale(m_slide[0].prop);
	mo->SetRatio(ratio);
	mo->SetAngle(mo_angle);

	if (mo_pos.x() > 0)
		pos = mo_pos;

	mo->reset(pos, dir, ortho);
	glutPostRedisplay();


}//void SetMagnet()

void GUI::SetMagnet( Vector2& _pos, Vector2& _dir )
{

	ratio = m_slide[1].prop;
	mo->SetMMScale(m_slide[0].prop);
	mo->SetRatio(ratio);

	Vector2 ortho(-_dir.y(), _dir.x());
	ortho *= ratio;

	mo->reset(_pos, _dir, ortho);

}

void GUI::SetMagnet( MagnetObject* sel )
{
	if (sel == NULL) {
		mo_pos = -1;
		return;
	}

	start = sel->GetGUIStart();
	end = sel->GetGUIEnd();

	mo_angle = sel->GetAngle();
	mo_pos = sel->Getpos() * 0.1f;

	SetMagnet();

	sel->Renderoff();

	//Vector2 _pos = sel->Getpos();
	//Vector2 _dir = sel->GetDirlength();
	//Vector2 ortho(-_dir.y(), _dir.x());
	//ortho *= ratio;

	//mo->reset(_pos, _dir, ortho);
}


void GUI::adjSize(){


	if(size.x() > 10.0f)
		size.x() = 10.0f;
	else if(size.x() < 0.05f)
		size.x() = 0.05f;

	if(size.y() >10.0f)
		size.y() = 10.0f;
	else if(size.y() < 0.05f)
		size.y() = 0.05f;

	if(ori < 0)
		ori = 0;
	
	ori = (double)((int)ori%360);
	



};//adjSize

void GUI::AddMagnet(){
	if (!mo) return;
	clock_t begin = clock();
	mo->MakeMag();
	clock_t makemag = clock();
	m_particleSystem->wbPlaceMagnet(mo);
	clock_t place = clock();
	mo = NULL;

	pMO = m_particleSystem->Vmagnet_size()-1;
	SelectMagnetPM0();

	printf("make mag : %lf\n", (double)(makemag - begin)/CLOCKS_PER_SEC); 
	printf("place : %lf\n", (double)(place - makemag)/CLOCKS_PER_SEC); 

	mo_angle = 0.0f;
	mo_pos = -1.f;

}//void AddMagnet()

void GUI::DelMagnet(){

	printf("delmagnet\n");

	if(m_particleSystem->Vmagnet_size() == 0)
		return;


	auto it =  m_particleSystem->Vmagnet_Begin();
	for(int i = 0; i<pMO; i++)
		it++;

	//auto it = m_particleSystem->Vmagnet_Back();
	delete (*it);

	pMO--; if (pMO < 0) pMO = 0;
	selected_mo = NULL;


	//m_particleSystem->Vmagnet_Pop();
	it = m_particleSystem->Vmagnet_Pop(it);
		
		
	m_particleSystem->ResetMagnet();
	glutPostRedisplay();
	printf("done\n");
};//DelMagnet()

void GUI::MoveMO(bool dir){

	if(dir && pMO >0)
		pMO--;
		
	else if(!dir && pMO < m_particleSystem->Vmagnet_size()-1)
		pMO++;
		
	SelectMagnetPM0();
	glutPostRedisplay();

}//MoveMO

void GUI::MoveMagnet(Vector2& target){

	if(m_particleSystem->Vmagnet_size() == 0)
		return;

	//printf("Moving....");

	auto it =  m_particleSystem->Vmagnet_Begin();
	for(int i = 0; i<pMO; i++)
		it++;

	target *= 10.f;
	Vector2 pos = (*it)->Getpos();

	Vector2 dir = target - moveStart;
	moveStart = target;

	(*it)->MoveMag(dir);
	m_particleSystem->ResetMagnet();
	//printf("done\n");
	glutPostRedisplay();


}//MoveMagnet

void GUI::DrawFrame(){

	Vector2 pos = Vector2(-1.0f, -1.0f);
	Vector2 size = Vector2(2.0f, 2.0f);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture[4]);

	float x = pos.x(), y = pos.y();
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y);
    glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y + size.y());
	glTexCoord2f(1.0f, 1.0f); glVertex2f(x + size.x(), y  + size.y());
	glTexCoord2f(1.0f, 0.0f); glVertex2f(x + size.x(), y);


	glEnd();
	glDisable(GL_TEXTURE_2D);

}//DrawFrame();

void GUI::DrawAllSlide(){

	DrawFrame();

	for(int i = 0; i<num_slide; i++)
		DrawSlide(m_slide[i].barpos, m_slide[i].prop, m_slide[i].str);
	
	Vector2 pos = m_slide[1].barpos + Vector2(0.f, spacing + 0.15f);
	DrawButton(pos);

	pos += Vector2(0.f, buttonsize.y() * 2 + 7.0f * spacing);
	DrawInfo(pos, m_particleSystem->GetnumParticle(), m_particleSystem->Vmagnet_size(), m_particleSystem->GetnumMagnetcells());

}//DrawAllSlide

void GUI::DrawSlide(Vector2 bar_pos, float prop, std::string str){

	glColor3f(0.1f, 0.1f, 0.1f);
	glRasterPos2f(bar_pos.x() + 0.07f, bar_pos.y() + barsize.y() + spacing/4.f);
	for(unsigned int  i=0; i<str.size(); ++i)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);

	 
	 std::stringstream ss; ss.precision(2); ss << prop; std::string st = ss.str();;
	  for(unsigned int  i=0; i<st.size(); ++i)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, st[i]);
	if(prop > 1.0f)
		prop = 1.0f;
	else if(prop<0.0f)
		prop = 0.0f;


	glBindTexture(GL_TEXTURE_2D, texture[0]);
	glEnable(GL_TEXTURE_2D);
	float x = bar_pos.x(), y = bar_pos.y();
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y + barsize.y());
    glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y);
	glTexCoord2f(1.0f, 1.0f); glVertex2f(x + barsize.x() + pointersize.x(), y );
	glTexCoord2f(1.0f, 0.0f); glVertex2f(x + barsize.x() + pointersize.x(), y + barsize.y());


	glEnd();
	

	glBindTexture(GL_TEXTURE_2D, texture[1]);
	y += 0.0087f;
	x += barsize.x() * prop;
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y + pointersize.y() + barsize.y() * 0.0462f);
    glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y+ barsize.y() * 0.0462f);
    glTexCoord2f(1.0f, 1.0f); glVertex2f(x + pointersize.x(), y+ barsize.y() * 0.0462f);
    glTexCoord2f(1.0f, 0.0f); glVertex2f(x + pointersize.x(), y + pointersize.y() + barsize.y() * 0.0462f);


	glEnd();



	glDisable(GL_TEXTURE_2D);





}//DrawSlide()

void GUI::DrawButton(Vector2 button_pos){

	button_pos.x() += 0.07f;

	//draw button 1
	std::string str = "Show Magnets";

	glRasterPos2f(button_pos.x() + buttonsize.x() + spacing/2.f, button_pos.y() + buttonsize.y()/3.f);
	for(unsigned int  i=0; i<str.size(); ++i)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);



	if(showMagnet)
		glBindTexture(GL_TEXTURE_2D, texture[2]);
	else
		glBindTexture(GL_TEXTURE_2D, texture[3]);

	glEnable(GL_TEXTURE_2D);
	float x = button_pos.x(), y = button_pos.y();
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y + buttonsize.y());
    glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y);
	glTexCoord2f(1.0f, 1.0f); glVertex2f(x + buttonsize.x(), y );
	glTexCoord2f(1.0f, 0.0f); glVertex2f(x + buttonsize.x(), y + buttonsize.y());
	glEnd();

	glDisable(GL_TEXTURE_2D);

//draw button2
	str = "Show Mag. Field";
	x = button_pos.x(), y = button_pos.y() + spacing;
	glRasterPos2f(x + buttonsize.x() + spacing/2.f, y + buttonsize.y()/3.f);
	for(unsigned int  i=0; i<str.size(); ++i)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);

	if(showmField)
		glBindTexture(GL_TEXTURE_2D, texture[2]);
	else
		glBindTexture(GL_TEXTURE_2D, texture[3]);

	glEnable(GL_TEXTURE_2D);
	
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y + buttonsize.y());
    glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y);
	glTexCoord2f(1.0f, 1.0f); glVertex2f(x + buttonsize.x(), y );
	glTexCoord2f(1.0f, 0.0f); glVertex2f(x + buttonsize.x(), y + buttonsize.y());
	glEnd();
	glDisable(GL_TEXTURE_2D);


	//draw button3
	str = "Show Stencil";
	x = button_pos.x(), y = button_pos.y() + spacing * 2;
	glRasterPos2f(x + buttonsize.x() + spacing/2.f, y + buttonsize.y()/3.f);
	for(unsigned int  i=0; i<str.size(); ++i)
		glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);

	if(showStencil)
		glBindTexture(GL_TEXTURE_2D, texture[2]);
	else
		glBindTexture(GL_TEXTURE_2D, texture[3]);

	glEnable(GL_TEXTURE_2D);

	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y + buttonsize.y());
	glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y);
	glTexCoord2f(1.0f, 1.0f); glVertex2f(x + buttonsize.x(), y );
	glTexCoord2f(1.0f, 0.0f); glVertex2f(x + buttonsize.x(), y + buttonsize.y());
	glEnd();
	glDisable(GL_TEXTURE_2D);







}//DrawButton

void GUI::DrawInfo(Vector2 startpos, int numParticle, int numMagnet, int numcell){


	float x = startpos.x()+ 0.07f;
	float y = startpos.y() - 0.12f;

	glRasterPos2f(x, y);

	std::stringstream ss; ss.width(10); ss << "# of Cells : " ; ss << numcell;
	 std::string str = ss.str();

	for(unsigned int  i=0; i<str.size(); ++i)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);


	y += spacing * 0.95f;
	ss.str(""); ss << "# of Magnets : " ; ss << numMagnet;
	str = ss.str();
	glRasterPos2f(x, y);
	for(unsigned int  i=0; i<str.size(); ++i)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);
	y += spacing * 0.95f;
	ss.str("");ss <<"# of Particles : " ;ss << numParticle;
	str = ss.str();
	glRasterPos2f(x, y);
	for(unsigned int  i=0; i<str.size(); ++i)
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);




}//DrawInfo

bool GUI::ControlSlide(int x, int y, int xlen, int ylen, bool button_up){

	
	Vector2 pos((float)x/xlen, (float)y/ylen); 
	pos.y() = 1 - pos.y();
	pos = pos *2.f - 1.f;

	int num;

	if(dir_x){
		if(barstart.y() > pos.y() || pos.y() > barstart.y() + barsize.y())
			return false;

		if(pos.x() < barstart.x())
			return false;


		//m_slide[i].barpos = startpos + Vector2(barsize.x() * i + 0.05f, 0.f);

		num = (pos.x() - barstart.x())/(spacing + barsize.x());


	}//if x direction
	else{
		if(barstart.x() > pos.x() || pos.x() > barstart.x() + barsize.x())
			return false;

		if(pos.y() < barstart.y())
			return false;


		//m_slide[i].barpos = startpos + Vector2(barsize.x() * i + 0.05f, 0.f);

		num = (pos.y() - barstart.y())/(spacing + barsize.y());


		if(num < num_slide && pos.y() > m_slide[num].barpos.y() + barsize.y())
			num = 99;

		if(pos.y() > m_slide[1].barpos.y() + spacing && pos.y() < m_slide[1].barpos.y() + spacing + buttonsize.y())
			num = 2;

	}// y direction



	if(num >= num_slide)
		if(button_up){

			float y = pos.y() - spacing - m_slide[1].barpos.y() - 0.15f;
			if(!(pos.x() > barstart.x() + 0.07f && pos.x() < barstart.x() + buttonsize.x() + 0.07f) )
				return false;

			if(y > 0 && y < buttonsize.y())
				showMagnet = !showMagnet;

			y = pos.y() - m_slide[1].barpos.y() - 2 * spacing - 0.15f;
			if(y > 0 && y < buttonsize.y())
				showmField = !showmField;

			y = pos.y() - m_slide[1].barpos.y() - 3 * spacing - 0.15f;
			if(y > 0 && y < buttonsize.y())
				showStencil = !showStencil;

			glutPostRedisplay();
			return false;
		}//if(button)
		else
			return false;


	else if(num > num_slide)
		return false;


	m_slide[num].prop = (pos.x() - m_slide[num].barpos.x() - buttonsize.x()/2)/barsize.x();
	if(m_slide[num].prop > 1.0f)
		m_slide[num].prop = 1.0f;
	SetMagnet(selected_mo);
	glutPostRedisplay();



	return true;




}//ControlSlide()



bool GUI::GuiInit(bool _dir_x, float _spacing){


	dir_x = _dir_x;
	spacing = _spacing;
	Vector2 startpos = barstart;
	if(!dir_x)
	for(int i = 0; i<num_slide; i++){
			m_slide[i].barpos = startpos + Vector2(0.f, (barsize.y() + spacing) * i);
			m_slide[i].prop = 0.5f;
		}//for all m_slide
	else
		for(int i = 0; i<num_slide; i++){
			m_slide[i].barpos = startpos + Vector2((barsize.x() + spacing) * i, 0.f);
		m_slide[i].prop = 0.5f;
	}//for all m_slide


	 m_slide[0].str = "Mag. Moment : ";
	 m_slide[1].str = "Mag. Asp. Ratio : ";

	return LoadTextureBMP();

}//GuiInit();

void GUI::RotateMagnet( Vector2& target )
{
	if(m_particleSystem->Vmagnet_size() == 0)
		return;

	//printf("Rotating....");

	auto it =  m_particleSystem->Vmagnet_Begin();
	for(int i = 0; i<pMO; i++)
		it++;

	Vector2 pos = (*it)->Getpos();
	target *= 10.f;

	Vector2 org = rotateStart - pos;
	org.normalize_safe();
	float angle1 = org.getAngle();

	Vector2 mov = target - pos;
	mov.normalize_safe();
	float angle2 = mov.getAngle();

	rotateStart = target;

	float angle = angle1 - angle2;
	(*it)->AddAngle(angle);
	//printf(" angle : %f ", angle);

	m_particleSystem->ResetMagnet();
	//printf("done\n");
	glutPostRedisplay();

	Vector2 wpos(5.0f, 5.0f);
	Vector2 localpos;
	localpos = wpos - (*it)->Getpos();
	localpos.rotate(angle);
}

bool GUI::FindMagnet( Vector2& pos )
{

	if (m_particleSystem->Vmagnet_size() == 0) return false;

	int temp = pMO;
	pMO = 0;

	for (auto it = m_particleSystem->Vmagnet_Begin(); it != m_particleSystem->Vmagnet_End(); it++, pMO++) {

		if ((*it)->isInMagnet(pos)) {
			selected_mo = (*it);
			glutPostRedisplay();
			return true;
		}

	}

	pMO = temp;

	return false;

}

void GUI::ModifyMagnet()
{

	if (m_particleSystem->Vmagnet_size() == 0) return;

	auto it = m_particleSystem->Vmagnet_Begin();

	if (pMO > (int)vMagnet.size()) pMO = vMagnet.size();

	for (int i=0; i<pMO; i++) it++;

	ratio = m_slide[1].prop;

	bool tomodify = false;
	
	if ((*it)->IsChangeRatio(ratio)) {
		tomodify = true;

	}
	if ((*it)->IsChangeMMScale(m_slide[0].prop)) {
		tomodify = true;
	}

}

void GUI::SelectMagnetPM0()
{
	if(m_particleSystem->Vmagnet_size() == 0)
		return;


	auto it =  m_particleSystem->Vmagnet_Begin();
	for(int i = 0; i<pMO; i++)
		it++;

	selected_mo = (*it);

}
